using Microsoft.Extensions.Logging;
using SeataNet.Core.Configuration;
using SeataNet.Core.Exceptions;
using SeataNet.Core.Protocol;
using System.Collections.Concurrent;
using System.Text.Json;

namespace SeataNet.Core.RPC
{
    /// <summary>
    /// RPC客户端通道管理器
    /// </summary>
    public interface IChannelManager
    {
        Task<T> SendAsync<T>(AbstractMessage message, CancellationToken cancellationToken = default) where T : AbstractMessage;
        Task SendOnewayAsync(AbstractMessage message, CancellationToken cancellationToken = default);
        void RegisterMessageHandler<T>(Func<T, Task<AbstractMessage>> handler) where T : AbstractMessage;
        void UnregisterMessageHandler<T>() where T : AbstractMessage;
    }

    /// <summary>
    /// 默认RPC客户端通道管理器
    /// </summary>
    public class DefaultChannelManager : IChannelManager, IDisposable
    {
        private readonly HttpClient _httpClient;
        private readonly SeataConfiguration _configuration;
        private readonly ILogger<DefaultChannelManager> _logger;
        private readonly ILoggerFactory _loggerFactory;
        private readonly ConcurrentDictionary<Type, Func<AbstractMessage, Task<AbstractMessage>>> _messageHandlers;
        private readonly ILoadBalancer _loadBalancer;
        private readonly IRetryPolicy _retryPolicy;
        private readonly ICircuitBreaker _circuitBreaker;
        private readonly IMessageSerializer _serializer;
        private readonly List<string> _serverAddresses;
        private volatile bool _disposed = false;

        public DefaultChannelManager(
            HttpClient httpClient,
            SeataConfiguration configuration,
            ILogger<DefaultChannelManager> logger,
            ILoggerFactory loggerFactory,
            ILoadBalancer? loadBalancer = null,
            IRetryPolicy? retryPolicy = null,
            ICircuitBreaker? circuitBreaker = null,
            IMessageSerializer? serializer = null)
        {
            _httpClient = httpClient;
            _configuration = configuration;
            _logger = logger;
            _loggerFactory = loggerFactory;
            _messageHandlers = new ConcurrentDictionary<Type, Func<AbstractMessage, Task<AbstractMessage>>>();
            _loadBalancer = loadBalancer ?? new RoundRobinLoadBalancer();
            _retryPolicy = retryPolicy ?? new FixedIntervalRetryPolicy(3, TimeSpan.FromMilliseconds(1000));
            _circuitBreaker = circuitBreaker ?? new DefaultCircuitBreaker(5, TimeSpan.FromMilliseconds(30000));
            _serializer = serializer ?? new JsonMessageSerializer(_loggerFactory.CreateLogger<JsonMessageSerializer>());
            
            // 解析服务器地址
            _serverAddresses = ParseServerAddresses(configuration.Transport.ServerAddress);
            
            if (_serverAddresses.Count == 0)
            {
                throw new ConfigurationException("未配置有效的Seata服务器地址");
            }
        }

        public async Task<T> SendAsync<T>(AbstractMessage message, CancellationToken cancellationToken = default) where T : AbstractMessage
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(DefaultChannelManager));
            }

            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            var messageType = message.GetType();
            _logger.LogDebug($"发送消息: {messageType.Name}, ID: {message.MessageId}");

            var attempt = 0;
            Exception lastException = null;

            while (_retryPolicy.ShouldRetry(attempt, lastException))
            {
                attempt++;
                var serverAddress = _loadBalancer.SelectServer(_serverAddresses);
                
                try
                {
                    return await _circuitBreaker.ExecuteAsync(async () =>
                    {
                        return await SendMessageAsync<T>(message, serverAddress, cancellationToken);
                    });
                }
                catch (CircuitBreakerOpenException ex)
                {
                    _logger.LogWarning(ex, "熔断器已打开，请求被拒绝");
                    throw;
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    _logger.LogWarning(ex, $"发送消息失败 (尝试 {attempt}): {messageType.Name}, 服务器: {serverAddress}");
                    
                    if (!_retryPolicy.ShouldRetry(attempt, ex))
                    {
                        break;
                    }
                    
                    var delay = _retryPolicy.GetDelay(attempt);
                    _logger.LogDebug($"等待 {delay.TotalMilliseconds}ms 后重试");
                    await Task.Delay(delay, cancellationToken);
                }
            }

            _logger.LogError(lastException, $"发送消息最终失败: {messageType.Name}");
            throw new RpcException($"发送消息失败: {messageType.Name}", lastException);
        }

        public async Task SendOnewayAsync(AbstractMessage message, CancellationToken cancellationToken = default)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(DefaultChannelManager));
            }

            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            var messageType = message.GetType();
            _logger.LogDebug($"发送单向消息: {messageType.Name}, ID: {message.MessageId}");

            var attempt = 0;
            Exception lastException = null;

            while (_retryPolicy.ShouldRetry(attempt, lastException))
            {
                attempt++;
                var serverAddress = _loadBalancer.SelectServer(_serverAddresses);
                
                try
                {
                    await SendOnewayMessageAsync(message, serverAddress, cancellationToken);
                    return;
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    _logger.LogWarning(ex, $"发送单向消息失败 (尝试 {attempt}): {messageType.Name}, 服务器: {serverAddress}");
                    
                    if (!_retryPolicy.ShouldRetry(attempt, ex))
                    {
                        break;
                    }
                    
                    var delay = _retryPolicy.GetDelay(attempt);
                    _logger.LogDebug($"等待 {delay.TotalMilliseconds}ms 后重试");
                    await Task.Delay(delay, cancellationToken);
                }
            }

            _logger.LogError(lastException, $"发送单向消息最终失败: {messageType.Name}");
            throw new RpcException($"发送单向消息失败: {messageType.Name}", lastException);
        }

        public void RegisterMessageHandler<T>(Func<T, Task<AbstractMessage>> handler) where T : AbstractMessage
        {
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            var messageType = typeof(T);
            _messageHandlers[messageType] = async (message) =>
            {
                if (message is T typedMessage)
                {
                    return await handler(typedMessage);
                }
                
                throw new InvalidOperationException($"消息类型不匹配: 期望 {messageType.Name}, 实际 {message.GetType().Name}");
            };

            _logger.LogDebug($"注册消息处理器: {messageType.Name}");
        }

        public void UnregisterMessageHandler<T>() where T : AbstractMessage
        {
            var messageType = typeof(T);
            _messageHandlers.TryRemove(messageType, out _);
            _logger.LogDebug($"取消注册消息处理器: {messageType.Name}");
        }

        private async Task<T> SendMessageAsync<T>(AbstractMessage message, string serverAddress, CancellationToken cancellationToken) where T : AbstractMessage
        {
            var serializedData = _serializer.Serialize(message);
            var content = new ByteArrayContent(serializedData);
            
            // 添加请求头
            content.Headers.Add("Content-Type", "application/octet-stream");
            content.Headers.Add("X-Message-Type", message.MessageCode.ToString());
            
            var response = await _httpClient.PostAsync(
                $"{serverAddress}/seata/message",
                content,
                cancellationToken);
            
            if (!response.IsSuccessStatusCode)
            {
                throw new RpcException($"服务器返回错误状态码: {response.StatusCode}");
            }
            
            var responseData = await response.Content.ReadAsByteArrayAsync(cancellationToken);
            var responseMessage = _serializer.Deserialize(responseData);
            
            if (!(responseMessage is T typedResponse))
            {
                throw new RpcException($"响应消息类型不匹配: 期望 {typeof(T).Name}, 实际 {responseMessage?.GetType().Name}");
            }
            
            return typedResponse;
        }

        private async Task SendOnewayMessageAsync(AbstractMessage message, string serverAddress, CancellationToken cancellationToken)
        {
            var serializedData = _serializer.Serialize(message);
            var content = new ByteArrayContent(serializedData);
            
            // 添加请求头
            content.Headers.Add("Content-Type", "application/octet-stream");
            content.Headers.Add("X-Message-Type", message.MessageCode.ToString());
            content.Headers.Add("X-Oneway", "true");
            
            var response = await _httpClient.PostAsync(
                $"{serverAddress}/seata/message",
                content,
                cancellationToken);
            
            // 单向消息不关心响应内容，只关心是否成功发送
            if (!response.IsSuccessStatusCode)
            {
                throw new RpcException($"服务器返回错误状态码: {response.StatusCode}");
            }
        }

        private List<string> ParseServerAddresses(string serverAddress)
        {
            var addresses = new List<string>();
            
            if (string.IsNullOrWhiteSpace(serverAddress))
            {
                return addresses;
            }
            
            // 支持多个地址，用逗号分隔
            var parts = serverAddress.Split(',', StringSplitOptions.RemoveEmptyEntries);
            
            foreach (var part in parts)
            {
                var address = part.Trim();
                
                // 如果没有协议前缀，添加http://
                if (!address.StartsWith("http://") && !address.StartsWith("https://"))
                {
                    address = "http://" + address;
                }
                
                // 如果没有端口，添加默认端口8091
                if (!address.Contains(":") || address.EndsWith(":"))
                {
                    address = address.TrimEnd(':') + ":8091";
                }
                
                addresses.Add(address);
            }
            
            return addresses;
        }

        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

            _disposed = true;
            _messageHandlers.Clear();
            _httpClient?.Dispose();
        }
    }

    /// <summary>
    /// JSON消息序列化器
    /// </summary>
    public class JsonMessageSerializer : IMessageSerializer
    {
        private readonly ILogger<JsonMessageSerializer> _logger;
        private readonly JsonSerializerOptions _options;

        public JsonMessageSerializer(ILogger<JsonMessageSerializer>? logger = null)
        {
            _logger = logger;
            _options = new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                WriteIndented = false,
                IncludeFields = true
            };
        }

        public byte[] Serialize(AbstractMessage message)
        {
            try
            {
                var json = JsonSerializer.Serialize(message, message.GetType(), _options);
                return System.Text.Encoding.UTF8.GetBytes(json);
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, $"序列化消息失败: {message.GetType().Name}");
                throw new RpcException($"序列化消息失败: {message.GetType().Name}", ex);
            }
        }

        public AbstractMessage Deserialize(byte[] data)
        {
            try
            {
                var json = System.Text.Encoding.UTF8.GetString(data);
                var document = JsonDocument.Parse(json);
                
                if (!document.RootElement.TryGetProperty("messageCode", out var messageCodeElement))
                {
                    throw new RpcException("消息中缺少messageCode属性");
                }

                var messageCode = (MessageType)messageCodeElement.GetInt32();

                // 直接创建消息对象并反序列化
                var message = MessageFactory.CreateMessage(messageCode);
                if (message == null)
                {
                    throw new RpcException($"未知消息类型: {messageCode}");
                }

                // 从json中填充消息属性
                var tempMessage = JsonSerializer.Deserialize(json, message.GetType(), _options);
                if (tempMessage is AbstractMessage abstractMessage)
                {
                    return abstractMessage;
                }

                return message;
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "反序列化消息失败");
                throw new RpcException("反序列化消息失败", ex);
            }
        }
    }
}